package cn.iocoder.yudao.module.resource.service.tag;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.resource.controller.admin.tag.vo.TagPageReqVO;
import cn.iocoder.yudao.module.resource.controller.admin.tag.vo.TagSaveReqVO;
import cn.iocoder.yudao.module.resource.dal.dataobject.tag.TagDO;
import cn.iocoder.yudao.module.resource.dal.mysql.tag.TagMapper;
import cn.iocoder.yudao.module.resource.events.RefreshTagEvent;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.resource.enums.ErrorCodeConstants.TAG_HAD_EXISTS;
import static cn.iocoder.yudao.module.resource.enums.ErrorCodeConstants.TAG_NOT_EXISTS;

/**
 * 标签 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class TagServiceImpl implements TagService {
    @Resource
    private TagMapper tagMapper;

    @PostConstruct
    public void init() {
        refreshTag(null);
    }

    @EventListener
    public void refreshTag(RefreshTagEvent redisEvent) {
        tagDOMapCache.refresh(getClass().getName());
    }

    @Getter
    private final LoadingCache<String, Map<Integer, TagDO>> tagDOMapCache = CacheUtils.buildCache(Duration.ofMinutes(60L),
            new CacheLoader<>() {

                @Override
                public Map<Integer, TagDO> load(String id) {
                    List<TagDO> tagDOList = tagMapper.selectList();
                    Map<Integer, TagDO> tagDOMapBuild = tagDOList.stream().collect(Collectors.toMap(TagDO::getId, c -> c));
                    log.info("刷新Tag缓存");
                    return tagDOMapBuild;
                }
            });

    @Override
    public synchronized Integer createTag(TagSaveReqVO createReqVO) {
        TagDO tagDO = tagMapper.getOne(createReqVO.getTagName());
        if (tagDO != null) {
            throw exception(TAG_HAD_EXISTS);
        }
        // 插入
        TagDO tag = BeanUtils.toBean(createReqVO, TagDO.class);

        tagMapper.insert(tag);
        // 返回
        return tag.getId();
    }

    @Override
    public void checkTagExist(List<Integer> idList) {
        for (Integer id : idList) {
            this.validateTagExists(id);
        }
    }

    @Override
    public void updateTag(TagSaveReqVO updateReqVO) {
        // 校验存在
        validateTagExists(updateReqVO.getId());
        // 更新
        TagDO updateObj = BeanUtils.toBean(updateReqVO, TagDO.class);
        tagMapper.updateById(updateObj);
    }

    @Override
    public void deleteTag(Integer id) {
        // 校验存在
        validateTagExists(id);

        // 删除
        tagMapper.deleteById(id);
    }

    private void validateTagExists(Integer id) {
        if (tagMapper.selectById(id) == null) {
            throw exception(TAG_NOT_EXISTS);
        }
    }

    @Override
    public TagDO getTag(Integer id) {
        return tagMapper.selectById(id);
    }

    @Override
    public List<TagDO> getTagList(List<Integer> tagIdList) {
        if (tagIdList == null || tagIdList.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        return tagMapper.selectBatchIds(tagIdList);
    }

    @Override
    public PageResult<TagDO> getTagPage(TagPageReqVO pageReqVO) {
        return tagMapper.selectPage(pageReqVO);
    }

    @Override
    public List<TagDO> getTagListByNames(List<String> tagNames) {
        return tagMapper.selectList(TagDO::getTagName, tagNames);
    }

    @Override
    public List<String> getTagListByIds(Collection<Integer> ids) {
        final Map<Integer, TagDO> tagDOMap = tagDOMapCache.getUnchecked(getClass().getName());

        List<String> tagList = new ArrayList<>(ids.size());
        for (Integer id : ids) {
            TagDO tagDO = tagDOMap.get(id);
            if (tagDO != null) {
                tagList.add(tagDO.getTagName());
            }
        }
        return tagList;
    }

}